/************************************************************************
 *
 * cycle_count_ts.h
 *
 * (c) Copyright 2004-2006 Analog Devices, Inc.  All rights reserved.
 * $Revision: 6 $
 ************************************************************************/

/*
   Platform specific functions to measure cycle counts
 */

#pragma once
#ifndef __NO_BUILTIN
#pragma system_header /* cycle_count_ts.h */
#endif

#ifndef __CYCLE_COUNT_TS_DEFINED
#define __CYCLE_COUNT_TS_DEFINED


/*  TS Processor Speed */
#ifndef __PROCESSOR_SPEED__

#if defined(__ADSPTS101__)
#define  __PROCESSOR_SPEED__       250000000     /* 250 MHz - EZ-Kit Rev 1.6 */
/*#define  __PROCESSOR_SPEED__       300000000      300 MHz - maximum setting*/ 

#elif defined(__ADSPTS201__)
#define  __PROCESSOR_SPEED__       500000000     /* 500 MHz - EZ-Kit Rev 1.1 */
/*#define  __PROCESSOR_SPEED__       600000000      600 MHz - maximum setting*/

#elif defined(__ADSPTS202__)
#define  __PROCESSOR_SPEED__       500000000      /* 500 MHz */

#elif defined(__ADSPTS203__)
#define  __PROCESSOR_SPEED__       500000000      /* 500 MHz */

#else
#error  PROCESSOR NOT SUPPORTED
#endif

#endif  /* !defined __PROCESSOR_SPEED__ */


/* Define low level macros to handle cycle counts */

/* Return current value in cycle count registers  */

#if defined(__ADSPTS101__)
/* Description of the algorithm used 
     1,2) First read cycle count registers
     3,4) Second read cycle count registers
     5)   Load 0x2 (overhead for second read)
     6,7) If value second read <= value first read,
          rollover occured => return second read
     6,8) If value second read > value first read, 
          return first read plus overhead for second read
 */
#define _GET_CYCLE_COUNT( _CURR_COUNT )              \
                        do {                         \
                             asm volatile            \
                             ("yr4 = CCNT0;; \n\t"   \
                              "yr5 = CCNT1;; \n\t"   \
                              "yr6 = CCNT0;; \n\t"   \
                              "yr7 = CCNT1;; \n\t"   \
                              "yr11 = r11 - r11; yr10 = 0x2;; \n\t"         \
                              "ylr9:8 = r7:6 - r5:4 (SU);;    \n\t"         \
                              "IF yale; DO, %0 = LSHIFT r7:6 BY 0;;   \n\t" \
                              "IF nyale; DO, %0 = r5:4 + r11:10 (SU);;\n\t" \
                              : "=ylL" (_CURR_COUNT)                        \
                              : : "yr4", "yr5", "yr6", "yr7", "yr8",        \
                                  "yr9", "yr10", "yr11", "YSTAT" );         \
                        } while (0)
#else   /* __ADSPTS101__ */
/*
   When reading CCNT0, the contents of CCNT1 is stored with a shadow
   write at the same time (thus reading the cycle count registers is an
   atomic operation). Reading CCNT1 thereafter will return the upper
   half of the cycle count register at the time CCNT0 has been read
   until CCNT1 is read again.
*/
#define _GET_CYCLE_COUNT( _CURR_COUNT )              \
                        do {                         \
                             asm volatile            \
                             ("yr4 = CCNT0;; \n\t"   \
                              "yr5 = CCNT1;; \n\t"   \
                              "%0  = yr5:4;; \n\t"   \
                              : "=yl" (_CURR_COUNT)  \
                              : : "yr4", "yr5" );    \
                        } while (0)
#endif  /* __ADSPTS101__ */
                                                           

#if defined( DO_CYCLE_COUNTS )

/* Return current value in cycle count register */
#define _START_CYCLE_COUNT( _CURR_COUNT )  _GET_CYCLE_COUNT( _CURR_COUNT )


/* Return cycle count minus measurement overhead incurred */

#if defined(__ADSPTS101__)
/* Description of the algorithm used
     1,2) First read cycle count registers
     3,4) Second read cycle count registers
     5,7) Add measurement overhead to start value
     6)   Load 0x2 (overhead for second read)
     8,9) If value second read <= value first read,
          rollover occured => choose second read minus overhead
          otherwise choose first read unadjusted
     10)  Compute final result
 */
#define _STOP_CYCLE_COUNT( _CURR_COUNT, _START_COUNT ) \
                        do {                           \
                             asm volatile              \
                             ("yr4 = CCNT0;; \n\t"     \
                              "yr5 = CCNT1;; \n\t"     \
                              "yr6 = CCNT0;; \n\t"     \
                              "yr7 = CCNT1;; \n\t"     \
                              "yr9  = r9 - r9;   yr8  = 0x8;; \n\t"      \
                              "yr11 = r11 - r11; yr10 = 0x2;; \n\t"      \
                              "ylr13:12 = %1   + r9:8 (SU);;  \n\t"      \
                              "ylr9:8   = r7:6 - r5:4 (SU);;  \n\t"      \
                              "IF yale; DO, ylr5:4 = r7:6 - r11:10(SU);;\n\t"\
                              "%0 = r5:4 - r13:12 (SU);;      \n\t"      \
                              : "=ylL" (_CURR_COUNT)                     \
                              : "yl"  (_START_COUNT)                     \
                              : "yr4", "yr5", "yr6", "yr7", "yr8",       \
                                "yr9", "yr10", "yr11", "yr12", "yr13",   \
                                "YSTAT" );                               \
                        } while (0)

#else   /* __ADSPTS101__ */ 
/*
   When reading CCNT0, the contents of CCNT1 is stored with a shadow
   write at the same time (thus reading the cycle count registers is an
   atomic operation). Reading CCNT1 thereafter will return the upper
   half of the cycle count register at the time CCNT0 has been read
   until CCNT1 is read again.
     1,2) Read cycle count register
     3,4) Add measurement overhead (=4) to start cycle count
     5)   Compute result: _CURR_COUNT = Result (1,2) - Result(3,4)
*/
#define _STOP_CYCLE_COUNT( _CURR_COUNT, _START_COUNT ) \
                        do {                           \
                             asm volatile              \
                             ("yr4 = CCNT0;; \n\t"     \
                              "yr5 = CCNT1;; \n\t"     \
                              "yr7 = r7 - r7; yr6 = 0x5;; \n\t"  \
                              "ylr7:6 = %1 + r7:6 (SU);;  \n\t"  \
                              "%0  = r5:4 - r7:6;;        \n\t"  \
                              : "=ylL" (_CURR_COUNT)             \
                              : "yl"  (_START_COUNT)             \
                              : "yr4", "yr5", "yr6", "yr7", "YSTAT" );\
                        } while (0)
#endif  /* __ADSPTS101__ */

#else   /* DO_CYCLE_COUNTS */

  /* Replace macros with empty statements if no cycle count facility required */
#define _START_CYCLE_COUNT( _CURR_COUNT )
#define _STOP_CYCLE_COUNT( _CURR_COUNT, _START_COUNT )

#endif  /* DO_CYCLE_COUNTS */
#endif  /* __CYCLE_COUNT_TS_DEFINED */
